package com.pan.servlet.impl;

import com.pan.servlet.MyHumbleContainer;
import com.pan.servlet.MyHumbleServlet;
import com.pan.servlet.annocation.HumbleServletRegister;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MyHumbleContainerImpl implements MyHumbleContainer {

    private Map<String, MyHumbleServlet> urlHumbleServlet = new HashMap<>();

    public MyHumbleContainerImpl(Map<String,MyHumbleServlet> urlHumbleServlet) {
        this.urlHumbleServlet = urlHumbleServlet;
    }

    public MyHumbleContainerImpl(Class anchor) {
        ClassLoader classLoader = anchor.getClassLoader();
        String pkn = anchor.getPackage().getName();
        URL resourceUrl = classLoader.getResource(pkn.replaceAll("\\.", "/"));
        String dirName = resourceUrl.getFile();
        try {
            dirName = URLDecoder.decode(dirName, Charset.defaultCharset().toString());
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        File dirFile = new File(dirName);

        for (File file : getClassFile(dirFile, null)) {
            String fullName = toFullName(pkn,file);
            Class<?> clazz = null;
            try {
                clazz = classLoader.loadClass(fullName);
            } catch (ClassNotFoundException e) {throw new RuntimeException(e);}
            if (clazz.isAnnotationPresent(HumbleServletRegister.class)&&MyHumbleServlet.class.isAssignableFrom(clazz)){
                String url = clazz.getAnnotation(HumbleServletRegister.class).url();
                MyHumbleServlet humbleServlet = null;
                try {
                    humbleServlet = (MyHumbleServlet) clazz.getConstructor().newInstance();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
                add(url, humbleServlet);
            }

        }
        //以后还是不要在写函数式编程里写复杂逻辑了，错误不好排查
//        getClassFile(dirFile, null).stream().map(classFile->toFullName(pkn,classFile)).map(className -> {
//                    try {
//                        return classLoader.loadClass(className);
//                    } catch (ClassNotFoundException e) {
//                        throw new RuntimeException(e);
//                    }
//                }).filter(c -> c.isAnnotationPresent(HumbleServletRegister.class))
//                .filter(c -> c.isAssignableFrom(MyHumbleServlet.class))
//                .forEach(c -> {
//                    try {
//                        String url = c.getAnnotation(HumbleServletRegister.class).url();
//                        System.out.println(url);
//                        MyHumbleServlet humbleServlet = (MyHumbleServlet) c.getConstructor().newInstance();
//                        add(url, humbleServlet);
//                    } catch (Exception e) {
//                        throw new RuntimeException(e);
//                    }
//                });
    }

    //转全限定名
    public String toFullName(String packName, File file) {
        String absolutePath = file.getAbsolutePath();
        absolutePath = absolutePath.replaceAll("\\\\|/", ".");
        int startIndex = absolutePath.indexOf(packName);
        int endIndex = absolutePath.lastIndexOf(".class");
        return absolutePath.substring(startIndex, endIndex);
    }

    private List<File> getClassFile(File file, List<File> list) {
        if (list == null) list = new ArrayList<>();
        if (file.isDirectory()) {
            for (File f : file.listFiles()) {
                if (f.getName().endsWith(".class")) {
                    list.add(f);
                } else if (f.isDirectory()) {
                    this.getClassFile(f, list);
                }
            }
        }
        return list;
    }

    public void setUrlHumbleServlet(Map<String, MyHumbleServlet> urlHumbleServlet) {
        this.urlHumbleServlet = urlHumbleServlet;
    }

    public void putHumbleServlet(String url, MyHumbleServlet servlet) {
        urlHumbleServlet.put(url, servlet);
    }

    @Override
    public MyHumbleServlet get(String url) {
        if (urlHumbleServlet.containsKey(url)) {
            return urlHumbleServlet.get(url);
        }
        return null;
    }

    @Override
    public void add(String url, MyHumbleServlet humbleServlet) {
        this.urlHumbleServlet.put(url, humbleServlet);
    }
}
